# encoding:gbk
import pandas as pd
import logging
import sys
from datetime import datetime
import sqlite3
import time

'''
初始参数：
初始量A，初始价格A1，格距C

盘中：
当前价格B，当前持仓量B1

if 初始量A + (初始价格A1 - 当前价格B) * 1000 * 格距C > 当前持仓量B1 + 500:
    买入: (初始量A + (初始价格A1 - 当前价格B) * 1000 * 格距C) - 当前持仓量B1
if 初始量A + (初始价格A1 - 当前价格B) * 1000 * 格距C < 当前持仓量B1 - 500:
    卖出: 当前持仓量B1 - (初始量A + (初始量A - 当前价格B) * 1000 * 格距C)
'''

class a():pass
A = a()

def init(ContextInfo):
    """Initialize context parameters"""
    ContextInfo.accID = '99057414'
    ContextInfo.set_account(ContextInfo.accID)
    ContextInfo.stock_symbols = ['513060.SH']  # 设置标的列表
    ContextInfo.stock_params = {
        '513060.SH': {'名称':'恒生医疗ETF', '类型':'ETF', '格距':1000, '拐点':0.003, '拐点上涨触发':1.01, '拐点下跌触发':0.99, '初始量':1000, '初始价格':0.531},
        '513090.SH': {'名称':'香港证券ETF', '类型':'ETF', '格距':500, '拐点':0.003, '拐点上涨触发':1.01, '拐点下跌触发':0.99, '初始量':1000, '初始价格':1.619},
        '510900.SH': {'名称':'H股ETF', '类型':'ETF', '格距':500, '拐点':0.003, '拐点上涨触发':1.01, '拐点下跌触发':0.99, '初始量':1000, '初始价格':1.113},
        '513980.SH': {'名称':'港股科技50ETF', '类型':'ETF', '格距':1000, '拐点':0.003, '拐点上涨触发':1.01, '拐点下跌触发':0.99, '初始量':1000, '初始价格':0.710},
        '164824.SZ': {'名称':'印度基金LOF', '类型':'ETF', '格距':500, '拐点':0.003, '拐点上涨触发':1.01, '拐点下跌触发':0.99, '初始量':1000, '初始价格':1.517}
    }
    ContextInfo.start = '20250505 09:30:00'
    ContextInfo.end = '20250506 15:00:00'
    A.order_list = set()
    # A.flag_dealed = {symbol: True for symbol in ContextInfo.stock_symbols}
    # A.base_prices = {key: value['初始价格'] for key, value in ContextInfo.stock_params.items()}
    A.stock_infos = {key:{} for key in ContextInfo.stock_symbols}
    for stk in A.stock_infos.keys():
        A.stock_infos[stk]['计数'] = 0
        A.stock_infos[stk]['基准价'] = 0
        A.stock_infos[stk]['最低价'] = 9999
        A.stock_infos[stk]['最高价'] = 0
        A.stock_infos[stk]['交易锁'] = False
    ContextInfo.run_time("check_order","1nSecond","2025-06-09 09:30:00")

def get_account(ContextInfo, accountid, datatype):
    """Get account data (placeholder, replace with actual implementation)"""
    accounts = get_trade_detail_data(accountid, datatype, 'account')
    result = {}
    for dt in accounts:
        result['总资产'] = dt.m_dBalance
        result['净资产'] = dt.m_dAssureAsset
        result['总市值'] = dt.m_dInstrumentValue
        result['总负债'] = dt.m_dTotalDebit
        result['可用金额'] = dt.m_dAvailable
        result['盈亏'] = dt.m_dPositionProfit
    return result

def get_holdings(accountid, datatype):
    """Get holdings data"""
    PositionInfo_dict = {}
    resultlist = get_trade_detail_data(accountid, datatype, 'POSITION')
    for obj in resultlist:
        stock_symbol = obj.m_strInstrumentID + '.' + obj.m_strExchangeID
        PositionInfo_dict[stock_symbol] = {
            '持仓量': obj.m_nVolume,
            '持仓成本': obj.m_dOpenPrice,
            '浮动盈亏': obj.m_dFloatProfit,
            '可用余额': obj.m_nCanUseVolume,
            '成交日期': obj.m_strOpenDate
        }
    return PositionInfo_dict


def get_bartime(ContextInfo, length=19):
    """Get current bar time"""
    bar_time = timetag_to_datetime(ContextInfo.get_bar_timetag(ContextInfo.barpos), '%Y-%m-%d %H:%M:%S')
    return bar_time[:length]

def exec_normal_transaction(ContextInfo, target_normal):  # 执行普通交易
    tick_data = ContextInfo.get_full_tick(target_normal)
    current_holdings = get_holdings(ContextInfo.accID, 'STOCK')
    
    for stk in target_normal:
        stk_amount = int(ContextInfo.stock_params[stk]['初始量'] + (ContextInfo.stock_params[stk]['初始价格'] - tick_data[stk]['lastPrice']) * 1000 * ContextInfo.stock_params[stk]['格距'])
        print(f"[-]下单数量：{stk_amount}")
        if stk_amount > current_holdings[stk]['持仓量'] + 500:
            stk_price = tick_data[stk]['askPrice'][1]
            passorder(23, 1101, ContextInfo.accID, stk, 11, stk_price, stk_amount, 1, ContextInfo)  # 买入：以卖2价即时下单
            A.stock_infos[stk]['交易锁'] = True
        elif stk_amount < current_holdings[stk]['持仓量'] - 500:
            stk_price = tick_data[stk]['bidPrice'][1]
            passorder(24, 1101, ContextInfo.accID, stk, 11, stk_price, stk_amount, 1, ContextInfo)  # 卖出：以买2价即时下单
            A.stock_infos[stk]['交易锁'] = True

def exec_guaidian_transaction(ContextInfo, target_guaidian):  # 执行拐点交易
    tick_data = ContextInfo.get_full_tick(target_guaidian)
    for stk in target_guaidian:
        if not A.stock_infos[stk]['交易锁']:
            current_price = round(tick_data[stk]['lastPrice'], 3)
            drop_threshold = ContextInfo.stock_params[stk]['拐点下跌触发']
            up_threshold = ContextInfo.stock_params[stk]['拐点上涨触发']
            turning_point_threshold = ContextInfo.stock_params[stk]['拐点']
            # 下跌趋势 Downtrend
            if round((current_price / A.stock_infos[stk]['基准价']), 3) < drop_threshold:
                # print(ContextInfo, stock_symbol, f"拐点触发|下跌趋势 - 最新价:{current_price}, 基准价:{base_price}, 最小价:{min_price}")
                if current_price < A.stock_infos[stk]['最低价']:
                    A.stock_infos[stk]['最低价'] = current_price
                    print(ContextInfo, stock_symbol, f"拐点触发|持续下跌 - 更新最低价: {A.stock_infos[stk]['最低价']}")
                elif current_price > A.stock_infos[stk]['最低价'] * (1 + turning_point_threshold):
                    print(ContextInfo, stock_symbol, f"拐点触发|下跌反弹 - 最新价: {current_price} > 最低价: {min_price} + 最低价 * {turning_point_threshold}")
                    target.append(stock_symbol)
            # 上涨趋势
            elif round((current_price / A.stock_infos[stk]['基准价']), 3) > up_threshold:
                print(ContextInfo, stock_symbol, f"拐点触发|上涨趋势 - 最新价:{current_price}, 基准价:{base_price}, 最高价:{max_price}")
                if current_price > A.stock_infos[stk]['最高价']:
                    A.stock_infos[stk]['最高价'] = current_price
                    print(ContextInfo, stock_symbol, f"拐点触发|持续上涨 - 更新最高价: {A.max_prices[stock_symbol]}")
                elif current_price < A.stock_infos[stk]['最高价'] * (1 - turning_point_threshold):
                    print(ContextInfo, stock_symbol, f"拐点触发|上涨回调 - 最新价:{current_price} < 最高价:{max_price} - 最高价 * {turning_point_threshold}")
                    target.append(stock_symbol)
    
    if target:
    # print(f'满足拐点触发的股票列表：{target}')
        exec_normal_transaction(ContextInfo, target)

def check_order(ContextInfo):  #检查委托订单，每秒执行一次，在init()中设置
    orders = get_trade_detail_data(ContextInfo.accID, 'STOCK', 'ORDER')
    if len(orders) > 0:
        for obj in orders:
            # 遍历委托订单，如果委托量==成交量，则加入委托字典，否则执行计数，达到10次（10秒），则取消委托
            if obj.m_strOrderSysID not in A.order_list:
                if obj.m_nVolumeTotalOriginal == obj.m_nVolumeTraded:  # 委托量==成交量
                    A.order_list.add(obj.m_strOrderSysID)
                else:
                    stk = '.'.join([obj.m_strInstrumentID, obj.m_strExchangeID])
                    if A.stock_infos[stk]['计数'] == 10:
                        A.stock_infos[stk]['计数'] = 0  #计数重置为0
                        cancel(obj.m_strOrderSysID, ContextInfo.accID, 'STOCK', ContextInfo)
                        print(f"[+]达到设置时间（10秒）未成交，撤单处理")
                    else:
                        A.stock_infos[stk]['计数'] += 1

def deal_callback(ContextInfo, dealInfo):
    stk = '.'.join([dealInfo.m_strInstrumentID, dealInfo.m_strExchangeID])
    A.stock_infos[stk]['基准价'] = dealInfo.m_dPrice
    A.stock_infos[stk]['最低价'] = dealInfo.m_dPrice
    A.stock_infos[stk]['最高价'] = dealInfo.m_dPrice
    A.stock_infos[stk]['交易锁'] = False
    print(f"[+]更新基准价：{stk} = {dealInfo.m_dPrice}")

def 测试函数_cancel_order(ContextInfo):
    orderlist = get_trade_detail_data(ContextInfo.accID, 'STOCK', 'ORDER')
    now = datetime.datetime.now()
    yymmdd = now.strftime('%y-%m-%d')
    for order in orderlist:
        # if order.m_nOrderStatus not in [48, 49, 53, 54, 56]:
        order_time = datetime.datetime.strptime(yymmdd + ' ' + order.m_strInsertTime, '%y-%m-%d %H%M%S')
        if order.m_strInsertTime <= '113000' and now.strftime('%H%M%S') >= '130000':
            second1 = (datetime.datetime.strptime('113000', '%H%M%S') - order_time).seconds
            second2 = (now - datetime.datetime.strptime('130000', '%H%M%S')).seconds
            second3 = second1 + second2
        else:
            seconds = (now - order_time).seconds
        if seconds >= 30 and can_cancel_order(order.m_strOrderSysID, ContextInfo.accID, 'STOCK'):
            cancel(order.m_strOrderSysID, ContextInfo.accID, 'STOCK', ContextInfo)
            print('委托时间：', order_time)
            print('当前时间：', now)
            print(f'撤单成功，时间长为：{seconds}')

def main(ContextInfo):  # 主处理逻辑
    bar_time = timetag_to_datetime(ContextInfo.get_bar_timetag(ContextInfo.barpos), '%Y%m%d%H%M%S')
    # 判断交易时间
    if bar_time[-6:] >= '093000' and bar_time[-6:] <= '150000':  # 交易时间
        # 如果基准价==-1：表示当天未成交，执行普通交易；否则表示已经有过成交，基准价已更新，执行拐点交易
        target_normal = []
        target_guaidian = []
        for stk in A.stock_infos.keys():
            if A.stock_infos[stk]['基准价'] == 0:
                target_normal.append(stk)
            else:
                target_guaidian.append(stk)
        if len(target_normal) > 0:
            exec_normal_transaction(ContextInfo, target_normal)  # 执行普通交易
        if len(target_guaidian) > 0:
            exec_guaidian_transaction(ContextInfo, target_guaidian)  # 执行拐点交易
    else:
        print('非交易时间')

def handlebar(ContextInfo):
    flag = 1  # 1: 主函数Main, 2: 测试Test
    if flag == 1:
        main(ContextInfo)
    elif flag == 2:
        test(ContextInfo)

def test(ContextInfo):
    current_holdings = get_holdings(ContextInfo.accID, 'STOCK')
    stks = ['000777.SZ','513060.SH']
    stk_amount = 1000
    for stk in stks:
        passorder(23, 1101, ContextInfo.accID, stk, 3, 0, stk_amount, '策略', 1, '10001', ContextInfo) 
    orders = get_trade_detail_data(ContextInfo.accID, 'STOCK', 'ORDER')
    print(f"[-]委托数据：")
    for obj in orders:
        print(f"委托量：{obj.m_nVolumeTotalOriginal}, 成交数量: {obj.m_nVolumeTraded}, 成交均价：{obj.m_dTradedPrice}, 投资备注：{obj.m_strRemark}")
    deals = get_trade_detail_data(ContextInfo.accID, 'STOCK', 'DEAL')
    print(f"[-]成交数据：")
    for obj in deals:
        print(f"成交数量: {obj.m_nVolume}, 成交均价：{obj.m_dPrice}, 投资备注：{obj.m_strRemark}")
        
    print(A.stock_infos)















